using System.Collections;
using System.Collections.Generic;
using Koroutine.Runtime.Command;
using Koroutine.Runtime.Condition;
using UnityEngine;

namespace Koroutine.Runtime.Core
{
    public class CoroutineScheduler
    {
        private readonly List<CoroutineExecutionHandle> _handles = new List<CoroutineExecutionHandle>();
        
        public int CoroutineCount => _handles.Count;

        public CoroutineExecutionHandle Schedule(IEnumerator coroutine)
        {
            var handle = new CoroutineExecutionHandle();
            handle.CoroutineStack.Push(new CoroutineContext()
            {
                Coroutine = coroutine,
            });
            
            _handles.Add(handle);

            return handle;
        }

        public void Update()
        {
            var handlesToPop = new List<CoroutineExecutionHandle>();

            foreach (var handle in _handles)
            {
                if (handle.ExitFlag != CoroutineExitFlag.None)
                {
                    if (handle.ExitFlag == CoroutineExitFlag.BreakTop)
                        handle.ExitFlag = CoroutineExitFlag.None;
                    
                    handlesToPop.Add(handle);
                    continue;
                }
                
                if (handle.ActiveCondition is ICondition condition)
                {
                    condition.Update();
                    if (condition.Check())
                    {
                        handle.ActiveCondition = null;
                    }
                    else
                    {
                        continue;
                    }
                }
                if (handle.ActiveEnumerator.MoveNext())
                {
                    var current = handle.ActiveEnumerator.Current;
                    if (current is ICondition cur)
                    {
                        handle.ActiveCondition = cur;
                    } else if (current is CoverCoroutine cover)
                    {
                        handle.Cover(cover.Enumerator);
                    }
                }
                else
                {
                    handlesToPop.Add(handle);
                }
            }

            if (handlesToPop.Count > 0)
            {
                foreach (var handle in handlesToPop)
                {
                    handle.CoroutineStack.Pop();
                    if (handle.ExitFlag == CoroutineExitFlag.BreakAll || handle.CoroutineStack.Count == 0)
                    {
                        _handles.Remove(handle);
                    }
                }
            }
        }
    }
}